/*
PearReview - The peer review assistant.
Copyright (C) 2009  Dimitrij Pankratz, Anton Musichin
http://www.pearreview.com, info@pearreview.com

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
package com.pearreview.ui.datepicker;

import java.sql.Date;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Vector;

public abstract class Holidays {

	private Vector<CalendarDay> days = new Vector<CalendarDay>(34);
	
	/**
	 * Returns all days listed as holidays.
	 * 
	 * @return
	 */
	public Vector<CalendarDay> getDays() {
		return days;
	}
	
	/**
	 * Returns the CalendarDay with additional information to given date or
	 * null if no information available.
	 * 
	 * Time will be ignored!
	 * 
	 * @param date
	 * @return
	 */
	public CalendarDay getDay(Calendar date) {
		GregorianCalendar gcal = new GregorianCalendar(
				date.get(Calendar.YEAR),
				date.get(Calendar.MONTH), 
				date.get(Calendar.DAY_OF_MONTH));
		
		return getDay(gcal);
	}
	
	/**
	 * Returns the CalendarDay with additional information to given date or
	 * null if no information available.
	 * 
	 * @param date
	 * @return
	 */
	public CalendarDay getDay(GregorianCalendar date) {
		
		for(CalendarDay d : days) {
		if( d.getTime() == date.getTime().getTime() )
		return d;
		}
		return null;
	}
	
	/**
	 * Returns true if the given date is a nationwide holiday, 
	 * otherwise false.
	 * 
	 * @param date
	 * @return
	 */
	public boolean isNationalHoliday(GregorianCalendar date) {
		
		for(CalendarDay d : days) {
			if( d.getTime() == date.getTimeInMillis()
				&& d.isHoliday() && d.isNationwide() )
				return true;
			}
		return false;
	}
	
	/**
	 * Returns true if the given date is a regional 
	 * but not nationwide holiday, otherwise false.
	 * 
	 * @param date
	 * @return
	 */
	public boolean isRegionalHoliday(GregorianCalendar date) {
		
		for(CalendarDay d : days) {
			if( d.getTime() == date.getTimeInMillis()
				&& d.isHoliday() && !d.isNationwide() )
				return true;
			}
		return false;
	}
	
	
	/**
	 * Calculates eastern in Gregorian calendar for given year. 
	 * 
	 * Uses Oudin's Algorithm for Calculating the Date of Easter in the 
	 * Gregorian Calendar.
	 * 
	 * Use it for not orthodox countries.
	 * 
	 * @param year
	 * @return
	 */
	public GregorianCalendar eastern(int year) {
		int c = year/100;
		int n = year - 19 * (year/19);
		int k = (c - 17)/25;
		
		int l1 = c - c/4 - (c-k)/3 + 19*n + 15;
		int l2 = l1 - 30*(l1/30);
		int l3 = l2 - (l2/28)*(1 - (l2/28) * (29/(l2+1)) * ((21-n)/11));
		
		int a1 = year + year/4 + l3 + 2 - c + c/4;
		int a2 = a1 - 7 * (a1/7);
		int l = l3 - a2;
		
		int month = 3 + (l + 40)/44;
		int day = l + 28 - 31*(month/4);
		
		return new GregorianCalendar(year, month-1, day);
	}
	
	
	/**
	 * Calculates eastern in Julian calendar for given year.
	 * 
	 * Use it for orthodox countries.
	 * 
	 * @param year
	 * @return
	 */
	public static GregorianCalendar easternJulian(int year) {
		int month, day;
		int a = year%19;
		int b = year%4;
		int c = year%7;
		
		int d = (19 * a + 15) % 30;
		int e = (2*b + 4*c + 6*d + 6)%7;
		
		if ((d+e) < 10) {
			month = 3;
			day = 22+d+e;
		} else {
			month = 4;
			day = d+e-9;
		}
		
		GregorianCalendar gc = new GregorianCalendar();
		gc.setGregorianChange(new Date(Long.MAX_VALUE));
		gc.set(year, month-1, day, 0, 0, 0);
		
		return gc;
	}
}
